
package com.tencent.weibo.api
{
	import com.tencent.weibo.core.WeiboConfig;
	import com.tencent.weibo.lang.MessageCollection;
	import com.tencent.weibo.log.LevelLogger;
	import com.tencent.weibo.operation.FileRequestOperation;
	import com.tencent.weibo.operation.IRequestOperation;
	import com.tencent.weibo.operation.URLRequestOperation;
	import com.tencent.weibo.support.URLEncoding;
	import com.tencent.weibo.support.WeiboUtil;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.FileReference;
	import flash.utils.setTimeout;
	
	import mx.logging.ILogger;

	/**
	 * 抽象的API调用，供其它的API类使用，您不需要实例化这个类
	 * 如果增加其它的API类，可以继承这个类
	 * @langversion 3.0
	 * @playerversion Flash 9
	 * @playerversion AIR 1.1
	 */	
	public class AbstractAPI extends EventDispatcher
	{
		/**
		 * 日志输出对象
		 */		
		public static var logger:ILogger = LevelLogger.getLogger("com.tencent.weibo.api.AbstractAPI");
		/**
		 * 持有对微博核心配置类的实例引用
		 */		
		public var config:WeiboConfig;
		/**
		 * 构造方法
		 * @param target
		 */		
		public function AbstractAPI(target:IEventDispatcher=null)
		{
			super(target);
			config = WeiboConfig.getInstance();
		}
		/**
		 * 将传入的参数，和基础参数(Oauth认证要求的参数)合并，并发送网络请求
		 * @param url API请求的网络地址
		 * @param attachParms 用户调用API传入的参数
		 * @param currentToken 传入Token(如果有的话)
		 * @param oauthSecret 传入密钥(如果有的话)
		 * @param method GET或POST
		 * @param format 返回的数据格式，默认是字符串，支持json和xml
		 * @param fileUploadMode 确定是否有文件上传
		 * @param attachFileParm 和fileUploadMode同时使用，确定文件表单域属性名称
		 * @param file 和fileUploadMode同时使用，文件引用
		 * @return 一个IRequestOperation实例
		 * 
		 */			
		public function consolidationParametersAndSend(url:String,attachParms:Object,currentToken:String=null,oauthSecret:String="",method:String="GET",format:String="string",fileUploadMode:Boolean=false,attachFileParm:String=null,file:FileReference=null):IRequestOperation
		{
			var basicParms:Object = config.getStandardParameters(currentToken);
			var parms:Object = WeiboUtil.margeObjects(basicParms,attachParms);
			for(var parmName:String in parms)
			{
				if(parms[parmName] != null)
					parms[parmName] = URLEncoding.encode(parms[parmName]);
			}
			parms.oauth_signature = config.getOauthSignature(method,url,parms,oauthSecret);
			var operation:IRequestOperation;
			if(fileUploadMode)
				operation = new FileRequestOperation(url,parms,format,attachFileParm,file);
			else
				operation = new URLRequestOperation(url,parms,method,format);
			operation.addEventListener(Event.COMPLETE,completeHandler);
			operation.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
			return operation;
		}
		/**
		 * 和consolidationParametersAndSend方法作用相似，如果是明确AccessToken之后调用的API，可以用这个方法简化参数传递
		 * @param url API请求的网络地址
		 * @param attachParms 用户调用API传入的参数
		 * @param method GET或POST
		 * @return 一个IRequestOperation实例
		 */		
		public function generateDataRequest(url:String,attachParms:Object,method:String="GET"):IRequestOperation
		{
			attachParms.format = config.dataFormat;
			return consolidationParametersAndSend(url,attachParms,config.oauthToken,config.oauthSecret,method,config.dataFormat);
		}
		/**
		 * 和generateDataRequest方法作用相似，用于执行带文件上传的操作
		 * @param url API请求的网络地址
		 * @param attachParms 用户调用API传入的参数
		 * @param attachFileParm 确定文件表单域属性名称
		 * @param file 文件
		 * @return 一个IRequestOperation实例
		 */		
		public function generateFileRequest(url:String,attachParms:Object,attachFileParm:String,file:FileReference):IRequestOperation
		{
			attachParms.format = config.dataFormat;
			return consolidationParametersAndSend(url,attachParms,config.oauthToken,config.oauthSecret,"POST",config.dataFormat,true,attachFileParm,file);
		}
		/**
		 * 验证AccessToken和密钥是否存在，这是成功调用API的前提条件
		 */		
		public function checkAccessToken():void
		{
			if(config.oauthToken == null || config.oauthSecret == null || config.oauthToken == "" || config.oauthSecret == "")
				logger.error("checkAccessToken:{0}",MessageCollection.accessTokenInvalid);
		}
		
		/**@private*/
		protected function completeHandler(event:Event):void
		{
			//check error
			if(event.target.dataFormat == "json" || event.target.dataFormat == "xml")
			{
				if(checkResultError(event.target.data,event.target.apiName))
					return;
			}
			logger.info(event.target.apiName+MessageCollection.requestSuccess);
			//remove listener
			(event.target as EventDispatcher).removeEventListener(Event.COMPLETE,completeHandler);
		}
		
		/**@private*/
		protected function errorHandler(event:IOErrorEvent):void
		{
			logger.error(event.target.apiName+MessageCollection.requestFaield);
			//remove listener
			(event.target as EventDispatcher).removeEventListener(IOErrorEvent.IO_ERROR,errorHandler);
		}
		
		/**@private*/
		protected function checkResultError(data:Object,apiName:String):Boolean
		{
			var ret:int = 0;
			var errcode:int = 0;
			var msg:String = "";
			ret = int(data.ret);
			errcode = int(data.errcode);
			msg = data.msg;
			if(ret != 0 || errcode != 0)
			{
				logger.error(apiName+": ret={0},errcode={1},msg='{2}'",ret,errcode,msg);
				return true;
			}
			return false;
		}
	}
}